package com.yanqu.road.server.manger.activity.operamask;

import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.operamask.OperaMaskConfig;
import com.yanqu.road.entity.activity.operamask.OperaMaskGameData;
import com.yanqu.road.entity.activity.operamask.OperaMaskSceneData;
import com.yanqu.road.entity.activity.operamask.OperaMaskUserData;
import com.yanqu.road.entity.activity.operamask.config.OperaMaskPaintBoxConfig;
import com.yanqu.road.entity.activity.operamask.config.OperaMaskSceneConfig;
import com.yanqu.road.entity.activity.operamask.config.OperaMaskSingConfig;
import com.yanqu.road.entity.activity.operamask.config.OperaMaskSkillConfig;
import com.yanqu.road.entity.activity.operamask.game.OperaMaskBlock;
import com.yanqu.road.entity.activity.operamask.game.OperaMaskSkill;
import com.yanqu.road.entity.activity.operamask.sanxiao.OperaMaskEliminateTip;
import com.yanqu.road.entity.enums.*;
import com.yanqu.road.entity.language.LanguageType;
import com.yanqu.road.entity.player.UserInfo;
import com.yanqu.road.logic.bussiness.activity.OperaMaskBusiness;
import com.yanqu.road.server.GameServer;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.operamask.OperaMaskModule;
import com.yanqu.road.server.gameplayer.module.season.SeasonRewardModule;
import com.yanqu.road.server.logic.mail.MailManager;
import com.yanqu.road.server.logic.season.args.WasheTimeLimitTaskArgs;
import com.yanqu.road.server.manger.MultipleLanguageMgr;
import com.yanqu.road.server.manger.activity.ActivityMgr;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.manger.player.UserMgr;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.property.Property;
import com.yanqu.road.utils.property.PropertyHelper;
import com.yanqu.road.utils.string.StringUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

public class OperaMaskMgr extends TempMgr {

    public static final int BLOCK_LIST_WIDTH = 7;
    public static final int BLOCK_LIST_HEIGHT = 7;
    public static final int MAX_RANDOM_SKILL_COUNT = 3;
    public static final int RED_COLOR = 3;

    private static OperaMaskConfig config = null;

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return false;
    }

    public static void reloadActivityData() {
        getLogger().info("reload opera mask begin");

        // 拿活动
        List<ActivityInfo> list = NormalActivityMgr.getOpenActivityInfoList(eActivityType.OperaMask.getValue());
        if (list.isEmpty()) {
            config = null;
            getLogger().info("reload opera mask finish, no activity in show time.");
            return;
        }
        ActivityInfo activityInfo = list.get(0);

        // 【生成配置】
        OperaMaskConfig tmpConfig = new OperaMaskConfig();

        tmpConfig.setActivityInfo(activityInfo);

        Map<String, ActivityConfig> activityConfigMap = NormalActivityMgr.getActivityConfigMap(activityInfo.getActivityId());
        tmpConfig.initActivityConfig(activityConfigMap);

        Map<Integer, List<OperaMaskSkillConfig>> skillConfigMap = OperaMaskBusiness.getOperaMaskSkillConfigMap(activityInfo.getActivityId());
        for (List<OperaMaskSkillConfig> skillConfigList : skillConfigMap.values()) {
            for (OperaMaskSkillConfig skillConfig : skillConfigList) {
                initOperaMaskSkillConfig(skillConfig);
            }
        }
        tmpConfig.setSkillConfigMap(skillConfigMap);

        tmpConfig.setSceneConfigMap(OperaMaskBusiness.getOperaMaskSceneConfigMap(activityInfo.getActivityId()));
        for (OperaMaskSceneConfig sceneConfig : tmpConfig.getSceneConfigMap().values()) {
            initOperaMaskSceneConfig(sceneConfig);
        }

        // 替换配置
        config = tmpConfig;

        // 在线玩家刷新
        for (GamePlayer gamePlayer : GamePlayerMgr.getAllOnlinePlayer()) {
            gamePlayer.getModule(OperaMaskModule.class).refreshData();
        }

        getLogger().info("reload opera mask finish, activityId {}.", activityInfo.getActivityId());
    }

    public static OperaMaskConfig getConfig() {
        return config;
    }

    public static ActivityInfo getActivityInfo() {
        return config == null ? null : config.getActivityInfo();
    }

    private static void initOperaMaskSceneConfig(OperaMaskSceneConfig sceneConfig) {
        Map<Integer, Long> unlockMap = new ConcurrentHashMap<>();
        if (!Objects.equals("0", sceneConfig.getUnlock()) && !Objects.equals("-1", sceneConfig.getUnlock())) {
            String[] split = sceneConfig.getUnlock().split("=");
            unlockMap.put(Integer.valueOf(split[0]), Long.valueOf(split[1]));
        }
        sceneConfig.setUnlockMap(unlockMap);

        sceneConfig.setUnlockSkillList(StringUtils.stringToIntegerList(sceneConfig.getUnlockSkills(), "\\|"));

        Map<Integer, OperaMaskPaintBoxConfig> paintBoxConfigMap = new ConcurrentHashMap<>();
        List<String> boxParam = StringUtils.stringToStringList(sceneConfig.getPaintBox(), "\\|");
        for (int level = 1; level <= boxParam.size(); level++) {
            String[] split = boxParam.get(level - 1).split("=");
            OperaMaskPaintBoxConfig tmp = new OperaMaskPaintBoxConfig(level, Integer.valueOf(split[0]), Integer.valueOf(split[1]));
            paintBoxConfigMap.put(tmp.getLevel(), tmp);
        }
        sceneConfig.setPaintBoxConfigMap(paintBoxConfigMap);

        sceneConfig.setAssessLimitList(StringUtils.stringToLongList(sceneConfig.getAssessLimit(), "\\|"));

        sceneConfig.setEffectParamList(StringUtils.stringToIntegerList(sceneConfig.getEffectParam(), "\\|"));

        int[] initBlockList = new int[sceneConfig.getDefaultList().length()];
        int index = 0;
        for (char c : sceneConfig.getDefaultList().toCharArray()) {
            initBlockList[index++] = c - '0';
        }
        sceneConfig.setInitBlockList(initBlockList);

        sceneConfig.setRewardList(StringUtils.stringToStringList(sceneConfig.getReward(), "\\|"));
    }

    private static void initOperaMaskSkillConfig(OperaMaskSkillConfig skillConfig) {
        skillConfig.setSkillParamList(StringUtils.stringToIntegerList(skillConfig.getSkillParam(), "\\|"));
    }

    /**
     * 计算技巧分
     */
    public static int calcSkillValue(long score, int singLevel) {
        OperaMaskSingConfig singConfig = config.getSingConfigMap().get(singLevel);
        long skillValue = score / singConfig.getBaseYaYun();
        return (int) skillValue;
    }

    /**
     * 获取解锁的技能
     */
    public static List<Integer> getUnlockSkillList(Map<Integer, OperaMaskSceneData> sceneDataMap, boolean unlockAll) {
        if (config == null) {
            return new ArrayList<>();
        }

        Set<Integer> skillSet = new HashSet<>();
        for (OperaMaskSceneData sceneData : sceneDataMap.values()) {
            boolean unlock = (sceneData.getStatus() == OperaMaskSceneData.STATUS_NEW_UNLOCK || sceneData.getStatus() == OperaMaskSceneData.STATUS_UNLOCK) || unlockAll;
            if (unlock) {
                OperaMaskSceneConfig sceneConfig = config.getSceneConfigMap().get(sceneData.getId());
                if (sceneConfig != null) {
                    skillSet.addAll(sceneConfig.getUnlockSkillList());
                }
            }
        }

        skillSet.remove(0); // 需要移除0

        return new ArrayList<>(skillSet);
    }

    /**
     * 初始盘面
     */
    public static List<List<OperaMaskBlock>> getInitBlockList(OperaMaskSceneConfig sceneConfig) {
        List<List<OperaMaskBlock>> listList = new ArrayList<>();
        int[] initBlockList = sceneConfig.getInitBlockList();

        int index = 0;
        for (int y = 0; y < BLOCK_LIST_HEIGHT; y++) {
            listList.add(new ArrayList<>());
            List<OperaMaskBlock> list = listList.get(y);
            for (int x = 0; x < BLOCK_LIST_WIDTH; x++) {
                list.add(new OperaMaskBlock(x, y, initBlockList[index++], eOperaMaskBlockType.NormalBlock.getValue()));
            }
        }
        return listList;
    }

    /**
     * 获取随机盘面
     */
    public static List<List<OperaMaskBlock>> getRandomBlockList(OperaMaskSceneConfig sceneConfig) {
        int width = BLOCK_LIST_WIDTH;
        int height = BLOCK_LIST_HEIGHT;
        int colorCount = config.getColorNum();

        Random random = new Random();

        Integer removeColor = -1;
        List<Integer> sceneEffect1004 = OperaMaskSkillLogic.getSceneSkillEffectList(sceneConfig, eOperaMaskSkillType.Skill1004);
        if (sceneEffect1004 != null) {
            removeColor = sceneEffect1004.get(0);
        }

        // 低概率事件，10次很稳了
        for (int i = 0; i < 10; i++) {

            // 先把格子填满
            List<List<OperaMaskBlock>> listList = new ArrayList<>();
            for (int y = 0; y < height; y++) {
                List<OperaMaskBlock> list = new ArrayList<>();
                for (int x = 0; x < width; x++) {
                    list.add(new OperaMaskBlock(x, y, 0, eOperaMaskBlockType.NormalBlock.getValue()));
                }
                listList.add(list);
            }

            // 随机颜色
            for (int y = 0; y < height; y++) {
                for (int x = 0; x < width; x++) {
                    List<Integer> list = getCanCreateColor(listList, colorCount, x, y);
                    if (removeColor != -1) {
                        list.remove(removeColor);
                    }
                    if (list.isEmpty()) {
                        // 走到这里说明有问题，生成个炸弹让他稳住
                        listList.get(y).get(x).setType(eOperaMaskBlockType.BombColorful.getValue());
                    } else {
                        int index = random.nextInt(list.size());
                        listList.get(y).get(x).setColor(list.get(index));
                    }
                }
            }

            // 看看能不能消除
            OperaMaskEliminateTip tip = OperaMaskEliminateLogic.getEliminateTip(listList, false, false);
            if (tip != null) {
                return listList;
            }

        }

        // 说明代码有问题
        throw new RuntimeException("OperaMaskMgr getRandomBlockList error!");
    }

    private static List<Integer> getCanCreateColor(List<List<OperaMaskBlock>> listList, int colorCount, int x, int y) {
        Set<Integer> removeSet = new HashSet<>();
        // 下面2个颜色相同
        if (y - 2 >= 0
                && listList.get(y - 1).get(x).getColor() == listList.get(y - 2).get(x).getColor()) {
            removeSet.add(listList.get(y - 1).get(x).getColor());
        }
        // 左边2个颜色相同
        if (x - 2 >= 0
                && listList.get(y).get(x - 1).getColor() == listList.get(y).get(x - 2).getColor()) {
            removeSet.add(listList.get(y).get(x - 1).getColor());
        }
        // 结果
        List<Integer> list = new ArrayList<>();
        for (int i = 1; i <= colorCount; i++) {
            if (!removeSet.contains(i)) {
                list.add(i);
            }
        }
        return list;
    }

    /**
     * 获取解锁的技能格子数
     */
    public static int getMaxSkillCount(Map<Integer, OperaMaskSceneData> sceneDataMap) {
        long sumScore = sceneDataMap.values().stream().mapToLong(OperaMaskSceneData::getScore).sum();

        int count = 0;
        for (Integer needScore : config.getPaintBoxUnlockList()) {
            if (sumScore >= needScore) {
                count++;
            } else {
                break;
            }
        }

        return count;
    }

    /**
     * 生成一份可选技能
     */
    public static List<Integer> getRandomSkillList(OperaMaskConfig config, OperaMaskUserData userData, OperaMaskGameData gameData) {

        List<Integer> allCanRandomSkillList = getAllCanRandomSkillList(userData, gameData);

        // 随机
        if (allCanRandomSkillList.size() > MAX_RANDOM_SKILL_COUNT) {
            Collections.shuffle(allCanRandomSkillList);
            allCanRandomSkillList = allCanRandomSkillList.stream().limit(MAX_RANDOM_SKILL_COUNT).collect(Collectors.toList());
        }

        // 触发保底
        if (gameData.getAllRandomTimes() % config.getRandomExistSkillStep() == 0) {
            Random random = new Random();
            if (random.nextInt(1000) < config.getRandomExistSkillPercent()) {
                // 没满级技能
                List<Integer> noMaxSkillList = new ArrayList<>();
                for (OperaMaskSkill skill : gameData.getSkillList()) {
                    List<OperaMaskSkillConfig> skillConfigList = config.getSkillConfigMap().get(skill.getSkillId());
                    if (skill.getSkillLevel() < skillConfigList.size()) {
                        noMaxSkillList.add(skill.getSkillId());
                    }
                }
                // 随机一个出来
                if (noMaxSkillList.size() > 0) {
                    int index = random.nextInt(noMaxSkillList.size());
                    int skillId = noMaxSkillList.get(index);
                    if (!allCanRandomSkillList.contains(skillId) && allCanRandomSkillList.size() > 0) {
                        // 替换保底技能
                        allCanRandomSkillList.set(random.nextInt(allCanRandomSkillList.size()), skillId);
                    }
                }
            }
        }

        // 新手引导技能
        int sumTopLv = userData.getSkillMaxLevelMap().values().stream().mapToInt(Integer::intValue).sum();
        if (sumTopLv == 0 && allCanRandomSkillList.size() >= 2) {
            int index = allCanRandomSkillList.indexOf(config.getGuideSkillId());
            if (index == -1) {
                // 中间的技能替换为指定技能
                allCanRandomSkillList.set(1, config.getGuideSkillId());
            } else if (index != 1) {
                // 中间的技能和指定技能交换位置
                allCanRandomSkillList.remove(index);
                allCanRandomSkillList.add(1, config.getGuideSkillId());
            }
        }

        return allCanRandomSkillList;
    }

    /**
     * 获取所有可随机技能
     */
    public static List<Integer> getAllCanRandomSkillList(OperaMaskUserData userData, OperaMaskGameData gameData) {

        List<OperaMaskSkill> skillList = gameData.getSkillList();
        List<Integer> unlockSkillList = getUnlockSkillList(userData.getSceneDataMap(), userData.getTokenList().contains(1));

        // 拿已满级技能
        List<Integer> maxLevelSkill = new ArrayList<>();
        for (OperaMaskSkill skill : skillList) {
            List<OperaMaskSkillConfig> skillConfigList = config.getSkillConfigMap().get(skill.getSkillId());
            if (skill.getSkillLevel() >= skillConfigList.size()) {
                maxLevelSkill.add(skill.getSkillId());
            }
        }

        // 拿可随机技能
        List<Integer> allList;
        boolean noEmptySkillSite = skillList.size() >= getMaxSkillCount(userData.getSceneDataMap());
        if(userData.getTokenList().contains(1)){
            noEmptySkillSite = skillList.size() >= config.getPaintBoxUnlockList().size();
        }
        if (noEmptySkillSite) {
            // 已选技能 减去 已满级技能
            allList = skillList.stream().filter(item -> !maxLevelSkill.contains(item.getSkillId())).map(OperaMaskSkill::getSkillId).collect(Collectors.toList());
        } else {
            // 全部技能 减去 已满级技能
            allList = unlockSkillList.stream().filter(item -> !maxLevelSkill.contains(item)).collect(Collectors.toList());
        }

        return allList;
    }

    /**
     * 复制一份盘面
     */
    public static List<List<OperaMaskBlock>> cloneBlock(List<List<OperaMaskBlock>> param) {
        List<List<OperaMaskBlock>> tmpBlock = new ArrayList<>();
        for (List<OperaMaskBlock> list : param) {
            List<OperaMaskBlock> tmp = new ArrayList<>();
            for (OperaMaskBlock block : list) {
                tmp.add(block.clone());
            }
            tmpBlock.add(tmp);
        }
        return tmpBlock;
    }

    /**
     * 获取油彩盒升级增加的步数
     */
    public static int getBoxUpgradeAddStep(OperaMaskGameData data) {
        int addStep = 0;

        if (config != null) {

            // 配置的步数
            OperaMaskSceneConfig sceneConfig = config.getSceneConfigMap().get(data.getSceneId());
            Map<Integer, OperaMaskPaintBoxConfig> boxConfigMap = sceneConfig.getPaintBoxConfigMap();
            OperaMaskPaintBoxConfig boxConfig = boxConfigMap.get(data.getBoxLevel());
            if (boxConfig != null) {
                addStep += boxConfig.getAddStep();
            }

            // 剧目效果
            List<Integer> sceneEffect1001 = OperaMaskSkillLogic.getSceneSkillEffectList(sceneConfig, eOperaMaskSkillType.Skill1001);
            if (sceneEffect1001 != null) {
                addStep += (sceneEffect1001.get(0) / 1000);
            }

        }

        return addStep;
    }

    /**
     * 计算剧目评级
     */
    public static int calcScenePingJi(OperaMaskConfig config, int sceneId, long score) {
        OperaMaskSceneConfig sceneConfig = config.getSceneConfigMap().get(sceneId);
        List<Long> list = StringUtils.stringToLongList(sceneConfig.getAssessLimit(), "\\|");
        int pingJi = 0;
        for (long needScore : list) {
            if (score >= needScore) {
                pingJi++;
            } else {
                break;
            }
        }
        return pingJi;
    }

    /**
     * 获取评级奖励
     */
    public static String getPingJiReward(OperaMaskConfig config, int sceneId, long score) {
        int pingJi = calcScenePingJi(config, sceneId, score);
        if (pingJi <= 0) {
            return "";
        }

        OperaMaskSceneConfig sceneConfig = config.getSceneConfigMap().get(sceneId);
        if ("0".equals(sceneConfig.getReward()) || sceneConfig.getRewardList().isEmpty()) {
            return "";
        }

        List<String> rewardList = sceneConfig.getRewardList();
        int index = Math.min(pingJi - 1, rewardList.size() - 1);
        return rewardList.get(index);
    }

    // ================= 自动结束剧目==================

    private final static Set<Integer> autoEndActivitySet = new HashSet<>();

    public static void autoEndScene() {
        OperaMaskConfig tmpConfig = config;
        if (tmpConfig == null) {
            return; // 没活动
        }
        ActivityInfo activityInfo = tmpConfig.getActivityInfo();
        if (!ActivityMgr.activityInRewardPeriod(activityInfo)) {
            return; // 不在领奖期
        }
        if (autoEndActivitySet.contains(activityInfo.getActivityId())) {
            return; // 活动已处理过
        }
        synchronized (autoEndActivitySet) {
            if (autoEndActivitySet.contains(activityInfo.getActivityId())) {
                return; // 活动已处理过
            }

            // 数据库有数据的要处理，没数据的不管他了
            List<OperaMaskUserData> userDataList = OperaMaskBusiness.getOperaMaskUserDataList(activityInfo.getActivityId());
            for (OperaMaskUserData userData : userDataList) {
                try {
                    Object playerLock = GamePlayerMgr.getPlayerLock(userData.getUserId());
                    synchronized (playerLock) {

                        // ================================================

                        // 在线就用在线的数据
                        GamePlayer player = GamePlayerMgr.getOnlinePlayer(userData.getUserId());
                        if (player != null) {
                            userData = player.getModule(OperaMaskModule.class).getUserData();
                        }
                        // 跳过已结束的
                        OperaMaskGameData gameData = userData.getGameData();
                        if (gameData == null) {
                            continue;
                        }

                        // 邮件发关卡奖励
                        String pingJiReward = getPingJiReward(config, gameData.getSceneId(), gameData.getScore());
                        if (!StringUtils.isNullOrEmpty(pingJiReward)) {

                            // 日志
                            getLogger().info("OperaMaskMgr autoEndScene activityId {} userId {} sceneId {} score {} reward {}.",
                                    activityInfo.getActivityId(), userData.getUserId(), gameData.getSceneId(), gameData.getScore(), pingJiReward);

                            // 改领奖状态
                            userData.setGameData(null);
                            OperaMaskBusiness.updateOperaMaskUserData(userData);

                            String language = LanguageType.LANGUAGE_DEFAULT;
                            UserInfo userInfo = UserMgr.getUserInfo(userData.getUserId());
                            if (userInfo != null) {
                                language = userInfo.getLanguage();
                            }
                            Property passReward = PropertyHelper.parseStringToProperty(pingJiReward);
                            MailManager.sendMail(userData.getUserId(), eMailType.SYSTEM.getValue(), PropertyHelper.parsePropertyToString(passReward),
                                    MultipleLanguageMgr.getContent(MailManager.OPERA_MASK_AUTO_END_SCENE_REWARD_CONTENT, language),
                                    MultipleLanguageMgr.getContent(MailManager.OPERA_MASK_AUTO_END_SCENE_REWARD_TITLE, language));
                        }

                    }

                    // =========================================================== 

                } catch (Exception e) {
                    getLogger().error("autoEndScene. activityId {}, userId {}", activityInfo.getActivityId(), userData.getUserId());
                }
            }

            // 记录一下
            autoEndActivitySet.add(activityInfo.getActivityId());
        }
    }

}
